#include "stdafx.h"
#include "xkImgBit16.h"

inline WORD xkImgBit16::GetPixelValue(int x,int y)
{
	WORD *pwImageData = (WORD*)m_pImgInfo->pImageData;
	if( ( NULL == pwImageData ) ||
		( x<0 ) || ( y<0 ) ||
		( x>=m_pImgInfo->nWidth)||
		( y>=m_pImgInfo->nHeight ) 
		)
	{
		return 0;
	}

	return pwImageData[y*m_pImgInfo->nWidth+x];
}

inline void xkImgBit16::SetPixelValue(int x,int y,WORD wValue)
{
	WORD *pwImageData = (WORD*)m_pImgInfo->pImageData;

	if( ( NULL == pwImageData ) ||
		( x<0 ) || ( y<0 ) ||
		( x>=m_pImgInfo->nWidth)||
		( y>=m_pImgInfo->nHeight ) 
		)
	{
		return;
	}

	pwImageData[y*m_pImgInfo->nWidth+x] = wValue;
}

#define DKQ_MIN(a,b) ( ( (a)<(b) ) ? (a):(b) ) 
#define DKQ_MAX(a,b) ( ( (a)>(b) ) ? (a):(b) ) 

int xkImgBit16::Filter(long* kernel, long Ksize, long Kfactor, long Koffset)
{
	int nNewKoffset = 0;
	if( Koffset > 0 )
	{
		nNewKoffset = (Koffset+1) * ( m_nGrayLevels >> 8 ) - 1;
	}

	long k2   = Ksize/2;
	long kmax = Ksize-k2;
	long b,i;

	long xmin,xmax,ymin,ymax;
	long xmin2,xmax2,ymin2,ymax2;
	xmin = ymin = 0;
	xmax = m_pImgInfo->nWidth;
	ymax = m_pImgInfo->nHeight;
	xmin2 = xmin + k2;
	xmax2 = xmax - kmax;
	ymin2 = ymin + k2;
	ymax2 = ymax - kmax;

	int nWidth = m_pImgInfo->nWidth;
	int nHeight = m_pImgInfo->nHeight;

	WORD* cPtr  = (WORD*)m_pImgInfo->pImageData;
	WORD* cPtr2 = (WORD*)m_xProBuf.GetIdleBuffer();
	if( NULL == cPtr2 )
	{
		return -1;
	}

	int iCount;
	int iY, iY2, iY1;
	if( Kfactor==0 ) 
	{
		Kfactor = 1;
	}

	long x,y,k,j;

	for(y=ymin;y<k2;y++)
	{
		iY = y*nWidth;
		memcpy(cPtr2+iY,cPtr+iY,nWidth*sizeof(WORD));
	}
	for(y=ymax-kmax;y<ymax;y++)
	{
		iY = y*nWidth;
		memcpy(cPtr2+iY,cPtr+iY,nWidth*sizeof(WORD));
	}
	for(y=ymin; y<ymax; y++)
	{
		for(x=xmin; x<k2; x++)
		{
			iY = y*nWidth+x;
			cPtr2[iY] = cPtr[iY];
		}
		for(x=xmax-kmax; x<xmax; x++)
		{
			iY = y*nWidth+x;
			cPtr2[iY] = cPtr[iY];
		}
	}

	for(y=ymin2; y<ymax2; y++)
	{
		for(x=xmin2; x<xmax2; x++)
		{
			iY = y*nWidth+x;
			{
				b=0;
				iCount = 0;
				iY2 = ((y-k2)*xmax);
				for(j=-k2;j<kmax;j++)
				{
					iY1 = iY2+x;
					for(k=-k2;k<kmax;k++)
					{
						i=kernel[iCount];
						b += cPtr[iY1+k] * i;
						iCount++;
					}
					iY2 += xmax;
				}
				cPtr2[iY] = DKQ_MIN(m_nMaxGray, DKQ_MAX(0,(int)(b/Kfactor + nNewKoffset)));
			}
		}
	}

	m_pImgInfo->pImageData = cPtr2;

	return 0;
}

int xkImgBit16::Edge(long Ksize)
{
	long k2 = Ksize/2;
	long kmax= Ksize-k2;

	long xmin,xmax,ymin,ymax;
	xmin = ymin = k2;
	xmax = m_pImgInfo->nWidth - kmax;
	ymax = m_pImgInfo->nHeight - kmax;

	int nWidth = m_pImgInfo->nWidth;

	WORD w1,w2,wGray;
	int nOffset = 0;
	WORD *pData = (WORD*)m_pImgInfo->pImageData;

	for(long y=ymin; y<ymax; y++)
	{
		for(long x=xmin; x<xmax; x++)
		{
			w1 = 0;
			w2 = m_nMaxGray;

			for(long j=-k2;j<kmax;j++)
			{
				for(long k=-k2;k<kmax;k++)
				{
					nOffset = (y+k)*nWidth + x+j;
					wGray = pData[nOffset];

					if( wGray > w1 ) w1 = wGray;
					if( wGray < w2 ) w2 = wGray;
				}
			}

			pData[ y*nWidth + x] = m_nMaxGray - abs(w1-w2);
		}
	}

	return 0;
}

int xkImgBit16::Rotate2( float fRotate )
{
	int nWidth = m_pImgInfo->nWidth;
	int nHeight = m_pImgInfo->nHeight;
	int nOffset = 0;

	WORD* pwData    = (WORD*)m_pImgInfo->pImageData;
	WORD* pwNewData = (WORD*)m_xProBuf.GetIdleBuffer();
	if( NULL == pwNewData )
	{
		return -1;
	}
	if( abs( fRotate - 90 ) < 1 )
	{
		long x,y;
		for (y = 0; y < nHeight; y++)
		{
			for (x = 0; x < nWidth; x++)
			{
				pwNewData[ (nWidth-1 - x)*nHeight+y ] = pwData[y*nWidth+x];			
			}
		}

		m_pImgInfo->nWidth  = nHeight;
		m_pImgInfo->nHeight = nWidth;

		m_pImgInfo->pImageData = pwNewData;
	}
	else if( abs( fRotate - 180 ) < 1 )
	{
		long x,y,y2;
		for (y = 0; y < nHeight; y++)
		{
			y2 = nHeight-y-1;
			for (x = 0; x < nWidth; x++)
			{
				pwNewData[y2*nWidth+nWidth-1-x] = pwData[y*nWidth+x];			
			}
		}

		m_pImgInfo->pImageData = pwNewData;
	}

	return 0;
}

int xkImgBit16::Resample2(long lNewWidth,long lNewHeight,DWORD dwMode)
{
	if( lNewWidth <=0 || lNewHeight<=0 )
	{
		return -1;
	}

	if( lNewWidth == m_pImgInfo->nWidth && 
		lNewHeight == m_pImgInfo->nHeight ) 
	{
		//image already correct size (just copy and return)
		return 0;
	}//if

	int nWidth = m_pImgInfo->nWidth;
	int nHeith = m_pImgInfo->nHeight;

	//calculate scale of new image (less than 1 for enlarge)
	float xScale, yScale;
	xScale = (float)nWidth / (float)lNewWidth;    
	yScale = (float)nHeith / (float)lNewHeight;

	WORD* pwData    = (WORD*)m_pImgInfo->pImageData;
	WORD* pwNewData = (WORD*)m_xProBuf.GetIdleBuffer();
	if( NULL == pwNewData )
	{
		return -1;
	}

	float sX, sY;         //source location
	long dX,dY;           //destination pixel (int value)

	for(dY=0; dY<lNewHeight; dY++)
	{
		sY = (dY + 0.5f) * yScale - 0.5f;
		for(dX=0; dX<lNewWidth; dX++)
		{
			sX = (dX + 0.5f) * xScale - 0.5f;

			pwNewData[ dY*lNewWidth+dX ] = GetPixelValue( (int)sX,(int)sY );
		}//for x
	}//for y

	m_pImgInfo->nWidth  = lNewWidth;
	m_pImgInfo->nHeight = lNewHeight;
	m_pImgInfo->pImageData = pwNewData;

	return 0;
}

int xkImgBit16::CompareValues(const void *elem1, const void *elem2)
{
	int* c1 = (int*)elem1;
	int* c2 = (int*)elem2;

	return (*c1 - *c2);
}

int xkImgBit16::Median( long Ksize )
{
	long k2 = Ksize/2;
	long kmax= Ksize-k2;
	long i,j,k;

	WORD* kernel = new WORD[Ksize*Ksize];

	long xmin,xmax,ymin,ymax;
	xmin = ymin = 0;
	xmax = m_pImgInfo->nWidth;
	ymax = m_pImgInfo->nHeight;

	int nWidth  = m_pImgInfo->nWidth;
	int nHeight = m_pImgInfo->nHeight;

	WORD* pwData    = (WORD*)m_pImgInfo->pImageData;
	WORD* pwNewData = (WORD*)m_xProBuf.GetIdleBuffer();
	memset(pwNewData,0,nHeight*nWidth*2);
	if( NULL == pwNewData )
	{
		return -1;
	}

	for(long y=ymin; y<ymax; y++)
	{
		for(long x=xmin; x<xmax; x++)
		{	
			for(j=-k2,i=0;j<kmax;j++)
			{
				for(k=-k2;k<kmax;k++, i++)
				{
					kernel[i] = GetPixelValue(x+j,y+k);
				}
			}

			qsort(kernel, i, sizeof(WORD), CompareValues);

			pwNewData[ y*nWidth+x] = kernel[i/2];		
		}
	}

	m_pImgInfo->pImageData = pwNewData;

	MySafeDeleteMAB(kernel);

	return 0;
}

int xkImgBit16::Contour()
{
	long Ksize = 3;
	long k2 = Ksize/2;
	long kmax= Ksize-k2;
	long i,j,k;
	WORD wmax;
	WORD pix1,pix2;

	long xmin,xmax,ymin,ymax;
	xmin = ymin = k2;
	xmax = m_pImgInfo->nWidth - kmax;
	ymax = m_pImgInfo->nHeight - kmax;

	int nWidth = m_pImgInfo->nWidth;

	WORD* pwData = (WORD*)m_pImgInfo->pImageData;

	for(long y=ymin; y<ymax; y++)
	{
		for(long x=xmin; x<xmax; x++)
		{
			pix1 = pwData[ y*nWidth+x ];
			wmax = 0;
			for(j=-k2, i=0;j<kmax;j++)
			{
				for(k=-k2;k<kmax;k++, i++)
				{
					pix2 = pwData[ (y+k)*nWidth+x+j ]; 
					if( (pix2-pix1)>wmax ) wmax = pix2;
				}
			}
			pwData[ y*nWidth+x ] = m_nMaxGray - wmax;	
		}
	}

	return 0;
}